/**
 * Représente une ressource
 * 
 * Chaque objet est associée à une requête HTML, un nom et son objet chargé (Document pour les pages HTML)
 * 
 * @param {String} name Le nom de la ressource
 */
function Ressource(name)
{
	/**
	 * Nom de la ressource
	 */
	var _name;
	/**
	 * Requête de la ressource
	 */
	var _request;
	/**
	 * Objet de la ressource
	 */
	var _object;
	/**
	 * True si la ressource est chargée, false sinon
	 */
	var _loaded;
	
	/**
	 * Renvoie le nom de la ressource
	 * 
	 * @return {String} nom de la ressource
	 */
	this.getName = function() { return _name; }
	/**
	 * Renvoie la requête liée à la ressource
	 * 
	 * @return {Request} requête
	 */
	this.getRequest = function() { return _request; }
	/**
	 * Renvoie l'objet correspondant à la ressource chargée
	 * 
	 * @return {Object} objet (Document, ...)
	 */
	this.getObject = function() { return _object; }
	this.isLoaded = function() { return _loaded; }
	
	
	/**
	 * Change la requête de la ressource
	 * 
	 * @param {Request} request la requête correspondante
	 */
	this.setRequest = function(request)
	{
		_request = request;
	};
	/**
	 * Change l'objet de la requête et indique que la ressource est chargée
	 * 
	 * @param {Object} l'objet liée (Document pour HTML, ...)
	 */
	this.setObject = function(object)
	{
		_object = object;
		_loaded = true;
	}
	
	/**
	 * Constructeur
	 * 
	 * @param {String} name nom de la ressource
	 */
	function _construct(name)
	{
		_name = name;
		_loaded = false;
	}
	
	_construct(name);
}

/**
 * Objet URL, représentant une URL et ses paramètres
 * 
 * @param {String} url la partie URL
 * @param {Object} params les paramètres
 * @param {String} type type de l'URL, URL.POST ou URL.GET
 */
function URL(url, params, type)
{
	this.url = url;
	this.params = params;
	this.type = type;
};

function PageURL(url, index)
{
	if (!(url instanceof URL))
		this.sendError("Le paramètre 'url' doit être une instance de la classe 'URL' !")
	
	this.url = url;
	this.page_index = index;
}

PageURL.$useError();

URL.parse = function(url)
{
	var params = {};
	if (url.indexOf("?") != -1)
	{
		var turl = url.substring(0,url.indexOf("?"));
		var sparams = url.substring(url.indexOf("?")+1);
		var aparams;
		if (sparams.indexOf("&") != -1)
			aparams = sparams.split("&");
		else
			aparams = [sparams];
		
		for (var i = 0; i < aparams.length; i++)
		{
			var aaparams = aparams[i].split("=");
			params[aaparams[0]] = aaparams[1];
		};
		
		return new URL(turl, params, URL.GET);
	}
}

/**
 * URL de type POST
 */
URL.POST = Request.POST;
/**
 * URL de type GET
 */
URL.GET = Request.GET;


/**
 * Classe représentant chaque site ou une recherche peut être effectuée
 * 
 * La classe est abstraite, et doit être étendue (extends), et définir les méthodes abstraites suivantes:
 * - String getName(): nom du site
 * - String getCodeName(): nom de code du site (alphanumérique et caractère _)
 * - Array<String> getRessourcesToLoad(): tableau des ressources à charger (icone, image, page html, ...)
 * 
 * - URL getFirstPageUrl(args): URL de la première page de la requête. args: les arguments de la recherche
 * - URL getPageAtUrl(numPage, websiteSearch): URL d'une page de la recherche. numPage: numéro de la page, websiteSearch: l'objet websiteSearch
 * - Page parseDomAndGetPage(domdoc): parse le document et renvoie la page associée, contenant les "Items" trouvés. domdoc: l'objet Document de la page à parser
 * 
 * - String renderItem(item): renvoie le rendu HTML de l'item en question
 * - Array<String> getLabelColumns(): renvoie les noms des colonnes correspondants aux données d'un objet
 * 
 * Il est possible d'utiliser les méthodes suivantes:
 * 
 * - String getRessourceUrl(ressource_name): Renvoie l'URL relative vers la ressource demandée
 * - Ressource getHtmlRessource(ressource_name): Renvoie la ressource demandée
 * - String parseWithRegExp(str, regexp): Renvoie les paramètres de la chaîne correspondant à la RegExp.
 * - HTMLElement[] parseWithDOMExp(element, domexp, typeResult): renvoie l'élément ou les éléments correspondant à une DOMExp sur un élément précis
 * - sendError(message): envoie une erreur
 * 
 */
function Website()
{
	var _ressources;
	this.oninit = null;
	
	var _this;
	
	/**
	 * Constructeur de la classe
	 */
	function _construct()
	{
		_ressources = [];
	}
	
	
	this.getName = function(args) { }
	this.getCodeName = function(args) { }
	this.getRessourcesToLoad = function() { }
	
	this.getFirstPageUrl = function(args) { }
	this.getPageUrlForId = function(id) { }
	// this.getPageAtUrl = function(numPage, websiteSearch) { }
	this.parseDomAndGetPage = function(domdoc) { }
	this.parseDomAndGetPageById = function(id, domdoc) { }
	
	// this.renderItem = function(item) { }
	this.getLabelColumns = function(columns) { }
	
	
	
	/**
	 * Renvoie l'URL relative complète à une ressource
	 * 
	 * @param {String} ressource_name le nom de la ressource
	 * 
	 * @return {String} l'URL relative complète
	 */
	this.getRessourceUrl = function(ressource_name)
	{
		return "ressources/"+this.getCodeName()+"/"+ressource_name;
	};
	
	/**
	 * Renvoie l'Objet Ressource en fonction de son nom
	 * 
	 * @param {String} ressource_name le nom de la ressource
	 * 
	 * @return {Ressource} l'objet Ressource correspondant ou null si non trouvé
	 */
	this.getHtmlRessource = function(ressource_name)
	{
		var res = null;
		for (var i = 0; i < count(_ressources); i++)
		{
			if (_ressources.name == ressource_name)
			{
				res = _ressources.element;
				break;
			}
		}
		return res;
	};
	
	/**
	 * Renvoie les paramètres trouvés dans une chaîne avec une RegExp
	 * 
	 * @param {String} str la chaîne à chercher
	 * @param {String} strregexp la RegExp
	 * 
	 * @return {Array} liste des résultats trouvés
	 */
	this.parseWithRegExp = function(str, strregexp)
	{
		var regexp = new RegExp(strregexp,"gim")
		var matches = regexp.exec(str)
		
		var result = [];
		
		if (matches)
			result = matches.slice(1);
		
		return result;
	};
	
	/**
	 * Renvoie l'élément HTML ou les éléments HTML d'une DOMExp
	 * 
	 * @param {Document, HTMLElement} element Elément où il faut utiliser la DOMExp
	 * @param {String} domexpstr La DOMExp a utilisé (voir la classe DOMExp pour plus de détail)
	 * @param {Boolean} oneResult true si un seul élément est demandé
	 * 
	 * @return {Array, HTMLElement} l'élément ou les éléments trouvés, résultat dépendant de oneResult
	 */
	this.parseWithDOMExp = function(element, domexpstr, oneResult)
	{
		if (typeof(oneResult) == "undefined")
			oneResult = false;
		
		var type_result = DOMExp.MULTIPLE_RESULT;
		if (oneResult)
			type_result = DOMExp.ONE_RESULT;
		
		var d = new DOMExp(domexpstr);
		
		return d.exec(element, type_result)
		
	};
	
	/**
	 * Renvoie l'élément HTML ou les éléments HTML de plusieurs DOMExp
	 * 
	 * @param {Document, HTMLElement} element Elément où il faut utiliser la DOMExp
	 * @param {Object} listdomexp La liste des DOMExp (sous la forme {nom: "domexp"})
	 * 
	 * @return {Object} l'objet ayant les même attributs que ceux envoyés, mais avec l'élément trouvé
	 */
	this.parseWithArrayOfDOMExp = function(element, listdomexp)
	{
		if (typeof(oneResult) == "undefined")
			oneResult = false;
		
		var type_result = DOMExp.ONE_RESULT;
		
		var result = {}
		
		for (var i in listdomexp)
		{
			if (typeof(listdomexp[i]) == "string")
			{
				var d = new DOMExp(listdomexp[i]);
				result[i] = d.exec(element,type_result);
			}
		}
		
		
		return result;
		
	};
	
	/**
	 * Lance une nouvelle recherche sur le site
	 * 
	 * Doit au moins contenir le paramètre 'search'
	 * 
	 * @param {Array} args les arguments de la recherche
	 */
	this.newSearch = function(args)
	{
		
		if (!isset(args))
			this.sendError(I18n.t("errors.Website.search_empty"))
		
		if (!isset(args.search) && !isset(args.id))
			this.sendError(I18n.t("errors.Website.search_and_id_empty"))
		
		if (isset(args.search) && isset(args.id))
			this.sendError(I18n.t("errors.Website.search_and_id"))
		
		var wsearch = new WebsiteSearch(args, this);
		return wsearch;
	};
	
	/**
	 * Méthode d'initialisation d'un Website
	 * 
	 * Charge les ressources et déclenche l'évènement oninit lorsque cela est terminé
	 */
	this.init = function()
	{
		var res = this.getRessourcesToLoad();
		for (var i = 0; i < res.length; i++)
		{
			var r = res[i]
			var ressource = new Ressource(r);
			var url = this.getRessourceUrl(r);
			var req = new Request(url,Request.GET);
			ressource.setRequest(req);
			_ressources.push(ressource);
			
			_this = this;
			
			req.onload = _onload_ressource
			req.start();
		}
	};
	
	/**
	 * Ecouteur déclenché à chaque fois qu'une ressource est finie de charger
	 * 
	 * @param {RequestEvent} e l'event associé
	 */
	function _onload_ressource(e)
	{
		// On cherche la ressource concernée par la requête
		for (var i = 0; i < _ressources.length; i++)
		{
			if (_ressources[i].getRequest() == e.getRequest())
				_ressources[i].setObject(e.getRequest().getResponseText());
		}
		
		// Si toute les ressources ont été chargés, lancement de l'évènement
		if (_getRessourcesLoaded() == _ressources.length)
		{
			if (typeof(_this.oninit) == "function")
				_this.oninit();
		}
	};
	
	/**
	 * Obtient toute les ressources qui ont été déjà chargées
	 * 
	 * @return {int} le nombre de ressources chargées
	 */
	function _getRessourcesLoaded()
	{
		var loaded = 0;
		// On parcourt les ressources et on regarde si chacune est chargée
		for (var i = 0; i < _ressources.length; i++)
		{
			if (_ressources[i].isLoaded())
				loaded++;
		}
		return loaded;
	};
	
	/**
	 * Envoie une erreur
	 * 
	 * @param {String} message le message d'erreur
	 */
	this.sendError = function(message)
	{
		var _mes = "{Website: "+this.getName()+"} "+message;
		throw(getNewError(_mes))
	}
	
	_construct();
}
Website.$abstract();
